// SPDX-FileCopyrightText: Adam Evyčędo
//
// SPDX-License-Identifier: AGPL-3.0-or-later

package transformers

import (
	"unicode"
	"unicode/utf8"

	"golang.org/x/text/transform"
)

func Replace(f func(r rune) []rune) transform.Transformer {
	return replaceF(f)
}

const runeErrorString = string(utf8.RuneError)

type replaceF func(r rune) []rune

func (replaceF) Reset() {}

func (t replaceF) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
	for nSrc < len(src) {
		r, _ := utf8.DecodeRune(src[nSrc:])
		if r == utf8.RuneError {
			if !atEOF && !utf8.FullRune(src[nSrc:]) {
				err = transform.ErrShortSrc
				break
			}
			if nDst+3 > len(dst) {
				err = transform.ErrShortDst
				break
			}
			dst[nDst+0] = runeErrorString[0]
			dst[nDst+1] = runeErrorString[1]
			dst[nDst+2] = runeErrorString[2]
			nSrc++
			continue
		}
		replacement := t(r)
		size := 0
		for _, r2 := range replacement {
			r2b := []byte(string(r2))
			size += len(r2b)
		}
		if nDst+size > len(dst) {
			err = transform.ErrShortDst
			break
		}
		for _, r2 := range replacement {
			r2b := []byte(string(r2))
			s := len(r2b)
			for i := 0; i < s; i++ {
				dst[nDst] = r2b[i]
				nDst++
			}
			nSrc++
		}
	}
	return
}

type Replacer interface {
	Replace(r rune) []rune
}

func IsNonAlphanum(r rune) bool {
	return !(unicode.IsLetter(r) || unicode.IsDigit(r))
}
